<!DOCTYPE html>
<html>
<!--
Copyright 2006 The Closure Library Authors. All Rights Reserved.

Use of this source code is governed by an Apache 2.0 License.
See the COPYING file for details.
-->
<head>
<title>Closure Unit Tests - goog.events.EventTarget</title>
<script src="../base.js"></script>
<script>
  goog.require('goog.events.Event');
  goog.require('goog.events.EventTarget');
  goog.require('goog.testing.jsunit');
</script>
</head>
<body>
<script>

  /**
   * Class that implements EventTarget and dispatches a custom event 'count'
   */
  function TargetClass() {
    this.count = 0;
  };
  goog.inherits(TargetClass, goog.events.EventTarget);

  TargetClass.prototype.increment = function() {
    this.count++;
    return this.dispatchEvent(new MyEvent());
  };

  TargetClass.prototype.reset = function() {
    this.count = 0;
  };


  /**
   * Class that is set up to listen to the target
   */
  function ListenerClass() {
    this.count = 0;
  };

  ListenerClass.prototype.reset = function() {
    this.count = 0;
  };

  ListenerClass.prototype.justListen1 = function(e) {
    this.count++;
  };

  ListenerClass.prototype.justListen2 = function(e) {
    this.count++;
  };

  ListenerClass.prototype.justListen3 = function(e) {
    this.count++;
  };

  ListenerClass.prototype.preventDefault = function(e) {
    this.count++;
    e.preventDefault();
  };

  ListenerClass.prototype.stopPropagation = function(e) {
    this.count++;
    e.stopPropagation();
  };

  ListenerClass.prototype.returnFalse = function(e) {
    this.count++;
    return false;
  };

  ListenerClass.prototype.handleEvent = function(e) {
    if (e.type == 'count') {
      this.count++;
    }
  };

  function MyEvent(obj) {
    this.type = 'count';
  }
  goog.inherits(MyEvent, goog.events.Event);

  /**
   * No listeners
   */
  function testNoListeners() {
    var target = new TargetClass();
    var listener = new ListenerClass();

    var result = target.increment();

    assertEquals(0, listener.count);
    assertTrue(result);

    assertEquals('0 listeners should be removed',
                 0, goog.events.removeAll(target));
  }


  /**
   * Basic test of listeners
   */
  function testBasicEventTarget() {
    var target = new TargetClass();
    var listener = new ListenerClass();

    goog.events.listen(target, 'count', listener.justListen1, false, listener);
    goog.events.listen(target, 'count', listener.justListen2, false, listener);
    goog.events.listen(target, 'count', listener.justListen3, false, listener);

    var result = target.increment();

    assertEquals(3, listener.count);
    assertTrue(result);

    assertEquals('3 listeners should be removed',
                 3, goog.events.removeAll(target));
  }

  /**
   * Just Capture
   */
  function testJustCapture() {
    var target = new TargetClass();
    var listener = new ListenerClass();

    goog.events.listen(target, 'count', listener.justListen1, true, listener);

    var result = target.increment();

    assertEquals(1, listener.count);
    assertTrue(result);

    assertEquals('1 listeners should be removed',
                 1, goog.events.removeAll(target));
  }

  /**
   * Just Bubble
   */
  function testJustBubble() {
    var target = new TargetClass();
    var listener = new ListenerClass();

    goog.events.listen(target, 'count', listener.justListen1, false, listener);

    var result = target.increment();

    assertEquals(1, listener.count);
    assertTrue(result);

    assertEquals('1 listeners should be removed',
                 1, goog.events.removeAll(target));
  }

  /**
   * Basic test of listeners
   */
  function testCaptureAndBubble() {
    var target = new TargetClass();
    var listener = new ListenerClass();

    goog.events.listen(target, 'count', listener.justListen1, true, listener);
    goog.events.listen(target, 'count', listener.justListen2, true, listener);
    goog.events.listen(target, 'count', listener.justListen3, true, listener);
    goog.events.listen(target, 'count', listener.justListen1, false, listener);
    goog.events.listen(target, 'count', listener.justListen2, false, listener);
    goog.events.listen(target, 'count', listener.justListen3, false, listener);

    var result = target.increment();

    assertEquals(6, listener.count);
    assertTrue(result);

    assertEquals('6 listeners should be removed',
                 6, goog.events.removeAll(target));
  }


  /**
   * Test of prevent default
   */
  function testPreventDefault() {
    var target = new TargetClass();
    var listener = new ListenerClass();

    goog.events.listen(target, 'count', listener.justListen1, false, listener);
    goog.events.listen(target, 'count', listener.justListen2, false, listener);
    goog.events.listen(target, 'count', listener.preventDefault, false,
                       listener);

    var result = target.increment();

    assertEquals(3, listener.count);
    assertFalse(result);

    assertEquals('3 listeners should be removed',
                 3, goog.events.removeAll(target));
  }


  /**
   * Test of stop propagation
   */
  function testStopPropagation() {
    var target = new TargetClass();
    var listener = new ListenerClass();

    goog.events.listen(target, 'count', listener.justListen1, true, listener);
    goog.events.listen(target, 'count', listener.stopPropagation, true,
                       listener);
    goog.events.listen(target, 'count', listener.justListen1, false, listener);
    goog.events.listen(target, 'count', listener.justListen2, false, listener);

    var result = target.increment();

    assertEquals(2, listener.count);
    assertTrue(result);

    assertEquals('4 listeners should be removed',
                 4, goog.events.removeAll(target));
  }


  /**
   * Test of stop propagation and prevent default
   */
  function testStopPropagationAndPreventDefaultAtCapture() {
    var target = new TargetClass();
    var listener = new ListenerClass();

    goog.events.listen(target, 'count', listener.preventDefault, true,
                       listener);
    goog.events.listen(target, 'count', listener.stopPropagation, true,
                       listener);
    goog.events.listen(target, 'count', listener.justListen1, false, listener);
    goog.events.listen(target, 'count', listener.justListen2, false, listener);

    var result = target.increment();

    assertEquals(2, listener.count);
    assertFalse(result);

    assertEquals('4 listeners should be removed',
                 4, goog.events.removeAll(target));
  }


  /**
   * Test of stop propagation and prevent default
   */
  function testStopPropagationAndPreventDefaultAtBubble() {
    var target = new TargetClass();
    var listener = new ListenerClass();

    goog.events.listen(target, 'count', listener.justListen2, true, listener);
    goog.events.listen(target, 'count', listener.stopPropagation, true,
                       listener);
    goog.events.listen(target, 'count', listener.justListen1, false, listener);
    goog.events.listen(target, 'count', listener.preventDefault, false,
                       listener);

    var result = target.increment();

    assertEquals(2, listener.count);

    // Should be true because stop propagation cancelled the listener that
    // prevented default
    assertTrue(result);

    assertEquals('4 listeners should be removed',
                 4, goog.events.removeAll(target));
  }


  /**
   * Test return false
   */
  function testReturnFalse() {
    var target = new TargetClass();
    var listener = new ListenerClass();

    goog.events.listen(target, 'count', listener.justListen1, false, listener);
    goog.events.listen(target, 'count', listener.returnFalse, false, listener);
    goog.events.listen(target, 'count', listener.justListen3, false, listener);

    var result = target.increment();
    assertEquals(3, listener.count);
    assertFalse(result);

    assertEquals('3 listeners should be removed',
                 3, goog.events.removeAll(target));
  }

  function testHandleEvent() {
    var target = new TargetClass();
    var listener1 = new ListenerClass();
    var listener2 = new ListenerClass();
    var listener3 = new ListenerClass();

    goog.events.listen(target, 'count', listener1, false);
    goog.events.listen(target, 'count', listener2, false);
    goog.events.listen(target, 'count', listener3, false);

    target.increment();
    target.increment();
    var result = target.increment();
    assertEquals(3, listener1.count);
    assertEquals(3, listener2.count);
    assertEquals(3, listener3.count);
    assertTrue(result);

    assertEquals('3 listeners should be removed',
                 3, goog.events.removeAll(target));

  }


  function testListenOnce() {
    var target = new TargetClass();
    var listener = new ListenerClass();

    goog.events.listenOnce(target, 'count', listener.justListen1, false,
                           listener);
    goog.events.listenOnce(target, 'count', listener.justListen2, false,
                           listener);
    goog.events.listenOnce(target, 'count', listener.justListen3, false,
                           listener);

    var result = target.increment();

    assertEquals('listener count', 3, listener.count);
    assertTrue(result);

    // Increment again. This time all the listeners should have been removed
    result = target.increment();

    assertEquals(3, listener.count);
    assertTrue(result);
    assertEquals('0 listeners should be removed',
                 0, goog.events.removeAll(target));

    // Increment again to make sure that unlisten works
    goog.events.listenOnce(target, 'count', listener.justListen1, false,
                           listener);
    goog.events.unlisten(target, 'count', listener.justListen1, false,
                         listener);

    result = target.increment();
    assertEquals(3, listener.count);
    assertTrue(result);
    assertEquals('0 listeners should be removed',
                 0, goog.events.removeAll(target));

    // We now test that we can unlisten in the listener without breaking things
    var f = function(e) {
      goog.events.unlisten(target, 'count', f, false);
      return listener.justListen1(e);
    };
    goog.events.listenOnce(target, 'count', f, false);

    result = target.increment();
    assertEquals(4, listener.count);
    assertTrue(result);
    assertEquals('0 listeners should be removed',
                 0, goog.events.removeAll(target));
  }

  function testUnlistenInListen() {
    var target = new TargetClass();
    var listener = new ListenerClass();

    var f = function(e) {
      goog.events.unlisten(target, 'count', listener.justListen1, false,
                           listener);
      goog.events.unlisten(target, 'count', f, false);
      goog.events.unlisten(target, 'count', listener.justListen3, false,
                           listener);
      listener.justListen2(e);
    };

    goog.events.listen(target, 'count', listener.justListen1, false, listener);
    goog.events.listen(target, 'count', f, false);
    goog.events.listen(target, 'count', listener.justListen3, false, listener);

    var result = target.increment();

    assertEquals('justListen3 should not be called', 2, listener.count);
    assertTrue(result);

    assertEquals('0 listeners should be removed',
                 0, goog.events.removeAll(target));
  }

  function testParentEventTarget() {
    var child = new TargetClass();
    var parent = new TargetClass();

    assertNull('Parent event target should default to null',
        child.getParentEventTarget());

    child.setParentEventTarget(parent);

    assertEquals('Parent event target should be set', parent,
        child.getParentEventTarget());

    var listener = new ListenerClass();
    goog.events.listen(parent, 'count', listener.justListen1, false, listener);
    child.increment();

    assertEquals('Event should have bubbled to the parent', 1,
        listener.count);
  }

</script>
</body>
</html>
